//*****************************************************************************
//  C++: HW1
//  Shragay Dror (ID:038778445)
//  Zilber Jenia (ID:313975492)
//*****************************************************************************



#include<iostream>
using namespace std;

#define EXPAND_VALUE 16


class intArray_t {

public:
	intArray_t();
	intArray_t(int minElem);
	~intArray_t();

//*****************************************************************************
//  get the number of elements in array
//*****************************************************************************
	const int getNumElem() const{
		return numElem;
	}

//*****************************************************************************
//  get capacity of the array 
//*****************************************************************************
	const int getCapac() const{
		return capac;
	}

//*****************************************************************************
//  insert new element in the end of the array (return 1 if succeeded) 
//*****************************************************************************
	int insertElem(const int& val){
		if (numElem == capac) expArr();
		pArr[numElem] = new int;
		*(pArr[numElem]) = val;
		++numElem;
		return 1;
	}

//*****************************************************************************
//  return first element (NULL if no elements in array)
//*****************************************************************************
	const int* getFirst() const{
		if (emptyArr())
			return NULL;
		return pArr[0];
	}

//*****************************************************************************
//  return last element (NULL if no elements in array)
//*****************************************************************************
	const int* getLast() const{
		if (emptyArr())
			return NULL;
		return pArr[numElem-1];
	}

//*****************************************************************************
//  return pointer to the first int==val (NULL if no such val )
//*****************************************************************************
	const int* find(const int& val) const{
		if (!emptyArr()){
			for(int i=0; i<numElem; ++i){
				if (*(pArr[i])==val )
					return pArr[i];
			}
		}
		return NULL;
	}

//*****************************************************************************
//  remove first element with specific value (return pointer to element)
//*****************************************************************************
	const int* removeElem(const int& val){
		if (!emptyArr()){
			for(int i=0; i<numElem; ++i){
				if (*(pArr[i])== val){
					int* tmp = pArr[i];
					
					// moving pointers one place
					for(int k=i; k<(numElem-1); ++k){
						pArr[k] = pArr[k+1];
					}
					
					--numElem;
					return tmp;
				}
			}
		}
		return NULL;
	}

//*****************************************************************************
//  remove and delete element with specific value
//	(print 1 if succeeded or if no such value)
//*****************************************************************************
	int deleteElem(const int& val){
		for(int i=0; i<numElem; ++i){
			if (*(pArr[i])== val){
				delete pArr[i];
				
				// moving pointers one place
				for(int k =i; k<(numElem-1); ++k){
					pArr[k] = pArr[k+1];
				}

				--numElem;
			}
		}
		return 1;
	}

//*****************************************************************************
//  remove all elements from array without deleting values
//  (return 1 if succeded)
//*****************************************************************************
	int removeAll(){
		numElem = 0;
		return 1;
	}

//*****************************************************************************
//  remove and delete all element from array
//  (return 1 if succeded)
//*****************************************************************************
	int deleteAll(){

		for(int i=0; i<numElem; ++i){
			delete pArr[i];
		}

		numElem = 0;
		return 1;
	}

//*****************************************************************************
//  put a new element after specific index in array
//  supposed that append not allowed if array is empty
//  return 0 if array is empty or no value at index ind
//*****************************************************************************
	int append(const int& ind, const int* elem ){
		if (numElem == 0) return 0;
		if (ind > numElem-1) return 0;

		// expand array if necessary
		if (numElem == capac) expArr();

		// moving elements after index
		for(int i=numElem; i>ind+1; --i){
			pArr[i] = pArr[i-1];
		}

		// insert elem at (ind+1)
		pArr[ind+1] = (int*)elem;

		++numElem;
		return 1;
	}

//*****************************************************************************
//  put a new element before specific index in array
//  supposed that prepend not allowed if array is empty
//  supposed that prepend allowed if numElem==ind
//  return 0 if array is empty or no value at index==(ind-1)
//*****************************************************************************
	int prepend(const int& ind, const int* elem ){
		// use append with (ind-1) if ind!==0
		if (ind != 0) {
			return append(ind-1, (int*)elem);
		}

		// if numElem==0 can't prepend at ind==0
		if (numElem == 0) {
			return 0;
		}

		// expand array if necessary
		if (numElem == capac) expArr();

		// moving elements after index
		for(int i=numElem; i>ind; --i){
			pArr[i] = pArr[i-1];
		}

		// insert elem at (ind)
		pArr[ind+1] = (int*)elem;

		++numElem;
		return 1;

	}

private:
	int ** pArr;
	int capac;                         // capacity of array
 	int numElem;					   // number of elements of array

	intArray_t(const intArray_t&);     //copy CTOR

//*****************************************************************************
//  expand array with EXPAND_VALUE
//*****************************************************************************
	int expArr(){
		int **tmp;
		tmp = new int*[capac+EXPAND_VALUE];
		
		// copy of old elements
		for (int i=0; i<capac; ++i){
			tmp[i] = pArr[i];
		}
		
		// delete old array
		delete [] pArr;

		pArr = tmp;	
		capac +=EXPAND_VALUE;
		return 1;
	}

//*****************************************************************************
//  check if the array is empty
//*****************************************************************************
	bool emptyArr() const{
		if (numElem == 0) return true;
		return false;
	}



};
intArray_t::intArray_t(){
	pArr = new int*[EXPAND_VALUE];	
	capac = EXPAND_VALUE;
	numElem = 0;
}
intArray_t::intArray_t(int minElem){
	pArr = new int*[minElem];
	capac = minElem;
	numElem = 0;
}
intArray_t::~intArray_t(){
	for (int i=0; i<numElem; ++i){
		delete pArr[i];
	}
	delete [] pArr;
}
int main(){

//******************************************************************************
//  test for getNumElem()/getCapac()/insertElem(const int&)/getFirst()/getLast()
//******************************************************************************
	intArray_t testArr;

	for (int i=0; i<20; ++i){
		testArr.insertElem(i);
	}

	testArr.insertElem(77);
	testArr.insertElem(111);
	testArr.insertElem(222);

	cout << "Number of elements: " << testArr.getNumElem() << "\n";
	cout << "Capacity: " << testArr.getCapac() << "\n";
	cout << "First value: " << *(testArr.getFirst()) << "\n";
	cout << "Last value: " << *(testArr.getLast()) << "\n";

//******************************************************************************
//  test for find(const int&)
//******************************************************************************
	cout << "Values are: ";
	for (int i=0; i<testArr.getCapac(); ++i){
		if (testArr.find(i) != NULL) 
			cout << *(testArr.find(i))  << ' ' ;
	}

	cout << "\n" << "find(222) = " << *(testArr.find(222));
	cout << "\n" << "find(77) = " << *(testArr.find(77));
	cout << "\n" << "find(111) = " << *(testArr.find(111));

	cout << "\n" << "find(100) = ";
	if ((testArr.find(100))==NULL) cout << "NULL";


//******************************************************************************
//  test for removeElem(const int&)/deleteElem(const int&)
//******************************************************************************
	cout << "\n" << "removeElem(77) = " << *(testArr.removeElem(77));
	cout << "\n" << "find(77) = ";
	if ((testArr.find(77))==NULL) 
		cout << "NULL";

	cout << "\n" << "removeElem(100) = ";
	if ((testArr.removeElem(100))==NULL) 
		cout << "NULL";

	cout << "\n" 
		 << "deleteElem(111) - print 1 if succeeded or if no such value: " 
		 << testArr.deleteElem(111);
	cout << "\n" << "find(111) = ";
	if ((testArr.find(111))==NULL) 
		cout << "NULL";
	
	cout << "\n" 
		 << "deleteElem(100) - print 1 if succeeded or if no such value " 
		 << testArr.deleteElem(100);
	cout << "\n" << "find(100) = ";
	if ((testArr.find(100))==NULL) 
		cout << "NULL";

//******************************************************************************
//  test for removeAll()/deleteAll()
//******************************************************************************
	testArr.removeAll();
	cout << "\n" << "find(0..19) values: ";
	for(int i=0; i<20; ++i){
		if ((testArr.find(i))==NULL) 
			cout << "NULL" << ' '; 
	}

	intArray_t testArr1(10);

	for (int i=0; i<11; ++i){
		testArr.insertElem(i);
		testArr1.insertElem(i);
	}

	cout << "\nValues of old array are: ";
	for (int i=0; i<testArr.getCapac(); ++i){
		if (testArr.find(i) != NULL) 
			cout << *(testArr.find(i))  << ' ' ;
	}

	cout << "\n";
	cout << "Number of elements of new array: " << testArr1.getNumElem() << "\n";
	cout << "Capacity of new array: " << testArr1.getCapac() << "\n";
	cout << "First value of new array: " << *(testArr1.getFirst()) << "\n";
	cout << "Last value of new array: " << *(testArr1.getLast()) << "\n";

	cout << "Values of new array are: ";
	for (int i=0; i<testArr1.getCapac(); ++i){
		if (testArr.find(i) != NULL) 
			cout << *(testArr.find(i))  << ' ' ;
	}

	testArr1.deleteAll();
	cout << "\n" << "find(0..19) values: ";
	for(int i=0; i<20; ++i){
		if ((testArr1.find(i))==NULL) 
			cout << "NULL" << ' '; 
	}

	for (int i=0; i<11; ++i){
		testArr1.insertElem(i);
	}

	cout << "\nValues of new array are: ";
	for (int i=0; i<testArr1.getCapac(); ++i){
		if (testArr1.find(i) != NULL) 
			cout << *(testArr1.find(i))  << ' ' ;
	}

//******************************************************************************
//  test for append(const int&, const int*)/prepend(const int&, const int*)
//******************************************************************************
	testArr1.deleteAll();
	
	for (int i=0; i<1; ++i){
		testArr1.insertElem(i);
	}
		
	int* px = new int;
	*px = 3;
	
	
	cout << "\n"
	     << "prepend of 3: ";
	if (testArr1.prepend(1,px)==1)
		cout << *(testArr1.find(3));
	else 
		cout << "NULL";

	int* ppx = new int;
	*ppx = 4;

	cout << "\n"
	     << "append of 4: ";
	if (testArr1.append(1,ppx)==1)
		cout << *(testArr1.find(4));
	else 
		cout << "NULL";


	cout << "\n\n\n";
	return 0;
}